package com.neu.flashmall.ms.service.impl;

import com.neu.common.constant.RedisRegion;
import com.neu.flashmall.ms.entity.SysMenu;
import com.neu.flashmall.ms.entity.SysRoleMenu;
import com.neu.flashmall.ms.mapper.SysMenuMapper;
import com.neu.flashmall.ms.mapper.SysRoleMenuMapper;
import com.neu.flashmall.ms.service.SysMenuService;
import com.neu.flashmall.ms.service.SysRoleMenuService;
import com.neu.flashmall.ms.vo.SysMenuItemVo;
import com.neu.flashmall.ms.vo.SysMenuVo;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

@Service
public class SysMenuServiceImpl implements SysMenuService {

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Resource
    private SysRoleMenuService sysRoleMenuService;

    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Resource
    private SysMenuService sysMenuService;

    private final static String DUPLICATE_ERROR = "权限名称或者url或者property或者icon重复，请更改";

    /**
     * 通过角色id获取该角色所拥有的SysMenu的id
     * @param role
     * @return
     */
    @Override
    public List<Long> getMenuByRole(Integer role) {
        List<Long> menuIdList = sysRoleMenuService.getMenuIdByRole(role);
        if(menuIdList.isEmpty()) return new ArrayList<>();
        return sysMenuMapper.selectAllByMenuId(menuIdList);
    }

    /**
     * 创建有层次关系的SysMenuVo
     * @return
     */
    @Override
    public SysMenuVo createSysMenuVoLevel() {
        SysMenuVo result = new SysMenuVo();

        List<SysMenu> level1 = this.sysMenuMapper.selectAllByLevel(1);
        List<SysMenuItemVo> itemLevel1 = this.createSysMenuItemVoList(level1);

        List<SysMenu> level2 = this.sysMenuMapper.selectAllByLevel(2);
        List<SysMenuItemVo> itemLevel2 = this.createSysMenuItemVoList(level2);

        List<SysMenu> level3 = this.sysMenuMapper.selectAllByLevel(3);
        List<SysMenuItemVo> itemLevel3 = this.createSysMenuItemVoList(level3);

        try {
            this.makeUpSysMenuItemVoList(itemLevel2,itemLevel3);
            this.makeUpSysMenuItemVoList(itemLevel1,itemLevel2);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        result.setData(itemLevel1);
        return result;
    }

    /**
     * 根据roleId获取该角色所有的SysMenu
     * @param roleId
     * @return
     */
    @Override
    public List<SysMenu> getAllSysMenuByRole(Long roleId) {
        List<SysMenu> sysMenuList = this.sysMenuMapper.selectByRoleId(roleId);
        return sysMenuList;
    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
                    key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).ALL_SYS_MENU_LIST"),
            @CacheEvict(cacheNames = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
                    key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).MENU_URL_TO_ID_MAP"),
            @CacheEvict(cacheNames = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
                    key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).ROLE_TO_MENU_ID_SET_MAP"),
            @CacheEvict(cacheNames = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
                    key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).generateRoleToMenuIdListKey('1')")
    })
    public String addSysMenu(SysMenu sysMenu) {
        if(this.checkDuplicate(sysMenu)){
            return DUPLICATE_ERROR;
        }
        if(StringUtils.isEmpty(sysMenu.getUrl())){
            sysMenu.setUrl("-");
        }
        int result = this.sysMenuMapper.insertSelective(sysMenu);
        SysRoleMenu sysRoleMenu = new SysRoleMenu();
        sysRoleMenu.setMenuId(sysMenu.getId());
        sysRoleMenu.setRoleId(1L);
        int result2 = this.sysRoleMenuMapper.insertSelective(sysRoleMenu);
        if(result > 0 && result2 > 0){
            return "添加权限成功";
        }
        return "数据库异常";
    }

    /**
     * 根据SysMenu的id删除所有的SysMenu以及，他的子SysMenu，已经在sys_role_menu清除所有相关的记录
     * @param id SysMenu的id
     * @param level SysMenu的等级
     * @return
     */
    @Override
    @Transactional
    @Caching(evict = {
            @CacheEvict(cacheNames = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
                    key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).ALL_SYS_MENU_LIST"),
            @CacheEvict(cacheNames = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
                    key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).MENU_URL_TO_ID_MAP")
    })
    public String deleteSysMenu(Long id,Integer level) {
        if(level == 1){
            //获取当前权限的所有二级子权限的id
            List<Long> level2IdList = this.sysMenuMapper.selectSonId(id);
            //获取二级子权限的所有三级子权限的id
            List<Long> allAboutId = this.sysMenuMapper.selectSonByIdList(level2IdList);
            allAboutId.addAll(level2IdList);
            allAboutId.add(id);
            //根据所有相关id删除所有SysMenu
            System.out.println(allAboutId);
            this.sysMenuMapper.deleteByParentIdList(allAboutId);
            //根据所有相关id删除所有相关的SysRoleMenu
            this.sysRoleMenuMapper.deleteByMenuIdList(allAboutId);
        }else if(level == 2) {
            List<Long> allAboutId = this.sysMenuMapper.selectSonId(id);
            allAboutId.add(id);
            this.sysMenuMapper.deleteByParentIdList(allAboutId);
            this.sysRoleMenuMapper.deleteByMenuIdList(allAboutId);
        }else{
            this.sysRoleMenuMapper.deleteByMenuId(id);
        }
        /**
         * 删除自己本地是SysMenu
         * 因为上述的删除SysMenu是根据parentId删除的，所以自己本身是没有在上述操作中删除的
         */
        int result = this.sysMenuMapper.deleteById(id);
        if(result <= 0){
            return "数据库异常";
        }

        return "删除权限成功";
    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
                    key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).ALL_SYS_MENU_LIST"),
            @CacheEvict(cacheNames = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
                    key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).MENU_URL_TO_ID_MAP"),
            @CacheEvict(cacheNames = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
                    key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).ROLE_TO_MENU_ID_SET_MAP")
    })
    public String updateSysMenu(SysMenu sysMenu) {
        if(this.checkDuplicate(sysMenu)){
            return DUPLICATE_ERROR;
        }
        if(StringUtils.isEmpty(sysMenu.getUrl())){
            sysMenu.setUrl("-");
        }
        int result = this.sysMenuMapper.updateByPrimaryKeySelective(sysMenu);
        if(result > 0){
            return "更新权限信息成功";
        }
        return "数据库异常";
    }


    @Override
    @Cacheable(value = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
        key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).ALL_SYS_MENU_LIST")
    public List<SysMenu> getAllSysMenu() {
        return this.sysMenuMapper.selectAll();
    }

    /**
     * 创建出一个map，key是SysMenu的url，value是该url对应的SysMenu的id
     * @return
     */
    @Override
    @Cacheable(value = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
            key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).MENU_URL_TO_ID_MAP")
    public HashMap<String, Long> getUrlToIdMap() {
        HashMap<String,Long> map = new HashMap<>();
        List<SysMenu> sysMenuList = this.sysMenuService.getAllSysMenu();
        for(SysMenu sysMenu : sysMenuList){
            map.put(sysMenu.getUrl(),sysMenu.getId());
        }
        return map;
    }

    private void makeUpSysMenuItemVoList(List<SysMenuItemVo> father,List<SysMenuItemVo> son) throws CloneNotSupportedException {
        Iterator<SysMenuItemVo> fatherIterator = father.iterator();
        while(fatherIterator.hasNext()){
            SysMenuItemVo f = fatherIterator.next();
            Iterator<SysMenuItemVo> sonIterator = son.iterator();
            List<SysMenuItemVo> children = new ArrayList<>();

            while(sonIterator.hasNext()){
                SysMenuItemVo s = sonIterator.next();
                if(s.getDetail().getParentId().equals(f.getId())){
                    children.add((SysMenuItemVo) s.clone());
                    sonIterator.remove();
                }

            }
            f.setChildren(children);
        }
    }

    private List<SysMenuItemVo> createSysMenuItemVoList(List<SysMenu> sysMenuList){
        List<SysMenuItemVo> result = new ArrayList<>();
        for(SysMenu i : sysMenuList){
            SysMenuItemVo itemVo = new SysMenuItemVo();
            itemVo.setDetail(i);
            itemVo.setId(i.getId());
            itemVo.setName(i.getName());
            result.add(itemVo);
        }
        return result;
    }

    /**
     * 判断SysMenu的name、url、property、icon是否重复。
     * 只有等级三的权限才允许重名
     * @param sysMenu
     * @return 重复返回true，不重复返回false
     */
    private boolean checkDuplicate(SysMenu sysMenu){
        List<SysMenu> sysMenuList = this.sysMenuMapper.selectDuplicate(sysMenu);
        if(sysMenuList.size() >= 2) return true;
        if(sysMenuList.size() == 0) return false;
        if(sysMenuList.get(0).getId().equals(sysMenu.getId()))return false;
        return true;
    }


}
